package domain;

import java.awt.Color;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.*;

import javax.swing.JOptionPane;

/**
 * Per 12 December 2012 this class replaces Lithoklasse. All its creating of input and 
 * output files and its exception handling for reading and writing is now in the class itself.
 * Before: 
 * and lithostratigraphy data pertinent to the model area under concern, typically from the 
 * lithoklasse.voleg and lithostratigrafie.voleg files within the .svp archive file.
 * The choice between lithoclass and lithostratigraphy is completely controlled by 
 * defining the proper input and output file names in the calling classes. Has method to write 
 * a 'layerTable' to  csv file (so either lithoclasses or lithostratigraphy).
 * Uses regex from http://java.sun.com/developer/technicalArticles/releases/1.4regex/
 * @author kooijmanj1
 *
 */
public class LayerProperty {
	private static final String TAB="\u0009";
	private int ncols;
	private int nrows;
	private String[][] layerPropertyTable ;
	private int[] layerIndices;
	private Iterator<Map.Entry<Integer, String>> layerKeys;
	public static Map<Integer, String> names;
	private static Hashtable<Integer, Integer> reds;
	private static Hashtable<Integer, Integer> greens;
	private static Hashtable<Integer, Integer> blues;
	public static Hashtable<Integer, Color> colors;
	public static Hashtable<Integer, Float> props;
	public static Hashtable<Integer, Color> colorsP;
	
	/**
	 * Constructs instance from file taking account of
	 * file extension .voleg (raw file) or .csv (neat file).
	 * Assigns values to attributes. Additional should false in case of
	 * the Lithoklasse or Lithostrategraphy data, and true for additional
	 * data like HeatCapacity.
	 * @param file
	 * @param type
	 */
	public LayerProperty(File file, boolean additional){
		System.out.println("Filename "+ file.getName());
		String[] name = (file.getName()).split("\\."); //Regex for literal period
		int len = name.length;
		System.out.println("Extensie " + len  + name[len-1]);
		if (name[len - 1].equals("csv")){
			readNeatLayerProperties(file);
		}
		else {
			readRawLayerProperties(file);
		}
		if(additional){
			populateAdditionalHashTables();
			System.out.println("Additional hashtables populated");
		}
		else{
			populateLayerHashTables();
			System.out.println("Hashtables populated");
		}
	}
	
	public int getColumnCount(){
		return ncols;
	}
	
	public int getRowCount(){
		return nrows;
	}
	
	public String[][] getLayerTable(){
		return layerPropertyTable;
	}
	
	public Iterator<Map.Entry<Integer, String>> getLayerKeys(){
		return layerKeys;
	}
	
	public int[] getLayerIndices(){
		return layerIndices;
	}
	
	
	/**
	 * lithoklasse.voleg and lithostratigrafie.voleg are unregularly formatted
	 * ascii files with separation by means of tabs between values so as to enable the 
	 * use of spaces and commas inside  the different values
	 * (Source: Hans-Georg Sobisch). This class convert the .voleg files, the raw files,
	 * into regularly comma separated value (csv) files. 
	 * @param file
	 * @throws IOException
	 */
	public void readRawLayerProperties(File file){
		ArrayList<String> list = new ArrayList<String>();
		StringBuffer sb = new StringBuffer();
		Pattern p = Pattern.compile(" ");
		Matcher m = null;
		boolean result = false;
		String line = null;
		//Replace spaces by dashes (Lithoklasse file); separation by tabs remains, so
		//now  strings are separated from numerical values as within strings single 
		// spaces are used and between values tabs are used.
		BufferedReader reader = null;
		try {
			reader  = new BufferedReader(new FileReader(file));
			line = reader.readLine();
			while (!(line == null || line.equals(""))){
				m = p.matcher(line);
				result = m.find();
				while(result){
					m.appendReplacement(sb, "-");
					result = m.find();
				}
				m.appendTail(sb);
				list.add(sb.toString());
				sb = new StringBuffer();
				line = reader.readLine();
			}
		} 
		catch (FileNotFoundException e) {
			//message("There is no file to be read")
		}
		catch (IOException e) {
			//
		}
		finally {
			if (reader != null){
				try { reader.close(); }
				catch ( IOException ioe){}
			}
		}
		// Determine number of rows  in list and number of elements in first row
		// to initialize LithoTable
		nrows = list.size();
		String firstRow = list.get(0);
		ncols = firstRow.split(TAB).length - 1;
		layerPropertyTable = new String[ncols][nrows];			
		// Transfer list values to lithoTable
		int y=0;
		for (String newLine : list){
			String[] elements = newLine.split(TAB);
			for (int x = 0; x < ncols; x++){
				layerPropertyTable[x][y] = elements[x];
			}
			y++;
		}
	}
	
	
	// write content of layerTable to file
	public void writeNeatLayerProperties(File file){
		PrintWriter writer = null;
		try {
			writer = new PrintWriter(
				new BufferedWriter(
					new FileWriter(file)));
			for(int j = 0; j < nrows; j++){
				String lithoLine = "";
				String separator = ",";
				for( int i = 0; i < ncols; i++){
					if(i == ncols - 1) {
						separator = "";
					}
					lithoLine = lithoLine + layerPropertyTable[i][j] + separator;
				}
				writer.println(lithoLine);
				System.out.println(lithoLine);
			}
			if(writer.checkError()) {
				System.out.println("Error during writing " + file.getName());
			}
		}
		catch (IOException e) {
			// doe iets
		}
		finally {
			if (writer != null){
				writer.close();
			}
		}
	}
	/**
	 * Reads either lithoklasse.csv or lithostratigrafie.csv
	 * and fills layerTable attribute of this class's instance.
	 */
	public void readNeatLayerProperties(File file){
		String line = "";
		ArrayList<String> lines = new ArrayList<String>();
		BufferedReader reader = null;
		try{
			reader = new BufferedReader(new FileReader(file));
			line = reader.readLine();
			while(line != null && line != ""){
				lines.add(line);
				line = reader.readLine();
			}
			nrows = lines.size(); //attribute
			ncols = lines.get(0).split(",").length; // attribute
		}
		catch (IOException e){
			JOptionPane.showMessageDialog(null, "Error reading " + file.getName());
		}
		finally {
			if (reader != null){
				try { reader.close(); }
				catch ( IOException ioe){}
			}
		}
		int row = 0;
		layerPropertyTable = new String[nrows][ncols];
		for(String ln : lines){
			int col = 0;
			String[] words = ln.split(",");
			for (String word : words){
				layerPropertyTable[row][col] = word;
				col++;
			}
			row++;			 
		}		
	}
	
	/**
	 * Should provide fast and transparent access to lithoklasse 
	 * and lithostratigrafie general by properties rather 
	 * than through a table with indexed access.
	 */
	private void populateLayerHashTables(){
		layerIndices = new int[nrows];
		names = new LinkedHashMap<Integer, String>();
		reds = new Hashtable<Integer, Integer>();
		greens = new Hashtable<Integer, Integer>();
		blues = new Hashtable<Integer, Integer>();
		colors = new Hashtable<Integer, Color>();
		for (int i = 0; i < nrows; i++){
			for(int j = 0; j < ncols; j++){
				int key = new Integer(layerPropertyTable[i][0]);
				layerIndices[i] = new Integer(layerPropertyTable[i][0]);
				System.out.println("key: " + key);
				names.put(key, layerPropertyTable[i][1]);
				reds.put(key, new Integer(layerPropertyTable[i][2]));
				greens.put(key, new Integer(layerPropertyTable[i][3]));
				blues.put(key, new Integer(layerPropertyTable[i][4]));
				colors.put(key, new Color(reds.get(key), greens.get(key), blues.get(key)));
			}
		}
		layerKeys = names.entrySet().iterator();
		while(layerKeys.hasNext()){
			Map.Entry<Integer,String> pairs = (Map.Entry<Integer,String>)layerKeys.next();
			System.out.println(pairs.getKey() + " = " + pairs.getValue());
		}	
	}
	/**
	 * Should provide fast and transparent access to additional
	 * properties provided separately and related color information.
	 */
	private void populateAdditionalHashTables(){ // for additional props and their colors
		 int r = 0;
		 int g = 0;
		 int b = 0;
		 props = new Hashtable<Integer, Float>(); // props is additional properties
		 colorsP = new Hashtable<Integer, Color>();
		 for (int i = 0; i < nrows; i++){
			for(int j = 0; j < ncols; j++){
				int key = new Integer(layerPropertyTable[i][0]);
				props.put(key, Float.parseFloat(layerPropertyTable[i][1]));
				r = new Integer(layerPropertyTable[i][2]);
				g = new Integer(layerPropertyTable[i][3]);
				b = new Integer(layerPropertyTable[i][4]);
				System.out.println("rgb = " + r + "," + g + "," + b);
				colorsP.put(key, new Color(r,g,b));
			}
		}
	}
}
